package main

import (
	"encoding/json"
	"fmt"
	"github.com/mitchellh/mapstructure"
	"reflect"
	"strconv"
)

type Product struct {
	Name  string  `mapstructure:"name"`
	Price float32 `mapstructure:"price"`
}

func main() {
	jsonStr := `{"name": "Product A", "price": "12.34"}`

	var m map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &m)

	decoderConfig := &mapstructure.DecoderConfig{
		DecodeHook: func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
			if from.Kind() == reflect.String && (to.Kind() == reflect.Float32 || to.Kind() == reflect.Float64) {
				str := data.(string)
				f, err := strconv.ParseFloat(str, 64)
				if err != nil {
					return nil, err
				}
				return f, nil
			}
			if from.Kind() == reflect.String && (to.Kind() == reflect.Int || to.Kind() == reflect.Int32 || to.Kind() == reflect.Int64) {
				str := data.(string)
				i, err := strconv.ParseInt(str, 10, 64)
				if err != nil {
					return nil, err
				}
				return i, nil
			}
			return data, nil
		},
		Result: &Product{},
	}

	decoder, err := mapstructure.NewDecoder(decoderConfig)
	if err != nil {
		fmt.Println("Decoder error:", err)
		return
	}

	err = decoder.Decode(m)
	if err != nil {
		fmt.Println("Decode error:", err)
		return
	}

	product := decoderConfig.Result.(*Product)

	fmt.Printf("Name: %s\nPrice: %f\n", product.Name, product.Price)
}
